﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;

namespace BerkelyAlgorithem2
{
    public partial class SlaveForm : Form
    {
        RunningClock clock;
        NeighbourTable Neighbours;
        Form1 ff;
        System.Threading.Thread t;
        System.Threading.Thread t2;
        Neighbour oldMaster;
        int drift = 0;
        int driftInTime = 0;
        Slave slave;
        int minO = int.MaxValue;
        int maxO = 0;
        Neighbour master;

        RunningClock driftClock;

        public SlaveForm(NeighbourTable N, Form1 f)
        {

            InitializeComponent();
            this.Neighbours = N;
            this.ff = f;
            CheckForIllegalCrossThreadCalls = false;
            clock = new RunningClock();
            driftClock = new RunningClock();

            //labels
            this.label3.Text = drift.ToString();
            foreach (Neighbour n in Neighbours.Neighbours)
            {
                if (n.IsMaster)
                {
                    master = n;
                }
            }

            clock.run();
            driftClock.run();

            threadFun();
            threadLabel();

            f.Visible = false;

        }

        public void threadFun()
        {
            t = new System.Threading.Thread(fun);
            t.Start();
        }

        public void threadLabel()
        {
            t2 = new System.Threading.Thread(formLabelUpdater);
            t2.Start();
        }

        ~SlaveForm()
        {
            if (t != null)
            {
                if (t.IsAlive)
                {
                    try
                    {
                        t.Abort();
                    }
                    catch
                    {

                    }
                }
            }

            if (t2 != null)
            {
                if (t2.IsAlive)
                {
                    try
                    {
                        t2.Abort();
                    }
                    catch
                    {

                    }
                }
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        public void formLabelUpdater()
        {
            while (true)
            {
                System.Threading.Thread.Sleep(9);
                try
                {
                    this.label1.Text = utils.DateTimeAsString(clock.CurrentTime);

                    this.offset.Text = clock.currOffset.ToString();

                    this.IPAddr.Text = master.Address.ToString();
                    findMin(clock.currOffset);
                    findMax(clock.currOffset);

                    if (drift != 0)
                        clock.setTime(drift * 2);

                    if (slave != null)
                        if (slave.offsetCounter != 0)
                            this.avg.Text = (slave.offsetsum / slave.offsetCounter).ToString();

                }
                catch
                {
                    // ff.electionsStartedExceptionWasThrown(oldMaster, this);
                    this.elections.Visible = true;
                    ff.Visible = true;
                    this.Close();
                }
            }
        }

        public void fun()
        {
            Console.WriteLine("the local NeighbourTable is:");

            int i = 0;
            Neighbours.iterationNumber += 2 * Neighbours.Neighbours.Count;
            foreach (Neighbour n in Neighbours.Neighbours)
            {
                n.syncPort = 9000 + Neighbours.iterationNumber + i;
                Console.WriteLine(n.Address + ":" + n.syncPort);
                i++;

                if (n.IsMaster)
                {
                    master = n;
                }
            }

            slave = new Slave(Neighbours, clock, driftClock);

            try
            {
                slave.start();
            }
            catch (ElectionStartedException e)
            {
                oldMaster = e.NeighbourPointer;
                oldMaster.IsAlive = false;
                ff.electionsStartedExceptionWasThrown(e.NeighbourPointer, this);
                ff.Visible = true;
                this.Close();
            }
        }

        //drift +
        private void button1_Click(object sender, EventArgs e)
        {
            clock.setTime(drift * 2);
            drift++;
            this.label3.Text = drift.ToString();
        }

        //drift -
        private void button2_Click(object sender, EventArgs e)
        {
            clock.setTime(drift * 2);
            drift--;
            this.label3.Text = drift.ToString();
        }

        private void findMin(int num)
        {
            num = Math.Abs(num);
            if (num < this.minO)
            {
                this.minO = num;
                this.min.Text = num.ToString();
            }
        }

        private void findMax(int num)
        {
            num = Math.Abs(num);
            if (num > this.maxO)
            {
                this.maxO = num;
                this.max.Text = num.ToString();
            }
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);

            if (t != null)
            {
                if (t.IsAlive)
                {
                    try
                    {
                        t.Abort();
                    }
                    catch
                    {

                    }
                }
            }

            if (t2 != null)
            {
                if (t2.IsAlive)
                {
                    try
                    {
                        t2.Abort();
                    }
                    catch
                    {

                    }
                }
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }


}
